--
-- Author:      name
-- DateTime:    2018-05-28 15:57:48
-- Description: 游戏主逻辑

local skynet = require "skynet"
local log = require "Log"
local config = require "configquery"
local Timer = require "timer"
local FSM = require "fsm"
local NodeMessage = require "NodeMessage"
local Universal = require "Universal"
local json = require "cjson"
require "common"

local mix_array = mix_array
local table_clone = table_clone
local floor = math.floor
local four_five = math.four_five
local random = math.random


local MachineBase = class("MachineBase")

function MachineBase:ctor(tableid,rule)
	self.close = false --关闭游戏
	self.nodeMessage = NodeMessage.new()
	--共用类
	self.universal = Universal.new()

	self.player_list = {} --玩家列表
	self.seat_list = {} --座位列表
	self.tableid = tableid --桌子id
	log.debug("________tableid___",tableid)
	self.gameid = getGameIdbyTable(tableid)
	self.roomid = getRoomType(tableid)
	local cfgname = getGameRoomConfig(self.gameid)
	log.debug("________self.roomid___",self.roomid,cfgname)
	local roomcfg = config[cfgname][self.roomid]

	log.debug("___roomcfg___",roomcfg)
	--配置信息
	self.maxSeatNum = roomcfg.max_num --最大座位数
	self.bottomNum = roomcfg.min_bet --底分
	self.tipRate = roomcfg.room_fee or 0 --服务费
	self.incomeRate = (100 - self.tipRate)/100 --收入占比
	self.minChip = tonumber(roomcfg.min_money) --入场最低分
	self.topChip = tonumber(roomcfg.max_money) --入场最高分
	self.room_flag = ""..self.tableid..os.time()--大局唯一标识
	--配置信息
	self.maxRound = 80 --最大轮数
	self.curRound = 0 --当前轮

	self.handlerStateTime = nil --定时器句柄
	self.operStartTime = 0 --当前状态的开始时间
	self.gmcards = {} --配牌列表
	self.tbCheatNum = {} --配牌标记
	self.paijuid = 0 --牌局ID
	self.closeHandler = nil --维护时关游戏定时器
	self.rule = rule --规则
	self.stock = nil --库存
	--各状态的时间
	self.stateTime = {

	}
	--计时器
	self.timer = Timer:new()

	self:reset()
end
---------------------------------------------------------
-- private
---------------------------------------------------------
--重置数据
function MachineBase:reset()
	--玩家自身状态
	for k,v in pairs(self.player_list) do 
		v.playing = false	
	end
	self.operStartTime = 0
end

--状态定时器
function MachineBase:setTime(time,callback,loop,param)
	if self.handlerStateTime then 
		self.timer:unregister(self.handlerStateTime)
		self.handlerStateTime = nil	
	end
	if not time then 
		return 
	end
	self.handlerStateTime = self.timer:register(time , param, callback,loop)	
end

function MachineBase:get_timer_left_time()
	return self.timer:left_time(self.handlerStateTime)
end

--更新大厅中传来的玩家数据
function MachineBase:updateProperty(playerid,data)
	local player = self.player_list[playerid]
	if not player then 
		return 
	end
	for k,v in pairs(data) do 
		player[k] = v
	end
end

--更新人数
function MachineBase:updatePlayerNum( )
	local num = self:getTablePlayerNum()

	self.nodeMessage:sendGlobalService('tablestate', 'set', self.tableid, num)
end

--桌子人数
function MachineBase:getTablePlayerNum()
	local num = 0
	for k,v in pairs(self.player_list) do
		num = num + 1
	end
	return num
end

--离线清除
function MachineBase:removePlayer()
	for k,v in pairs(self.player_list) do 	
		if v.disconnect or v.chip < self.minChip  then 	
			if  v.chip < self.minChip then 
				local data = {nt_kick_table = {
					playerid = k,
					content = '金币不足请离场！',
				}}
				self:sendMessage(k,data)
			end			
			--设置玩家所在桌子id为0	
			self:sendGate(v, 'update_tableid', 0)
			self:sitUp(k)
			self.player_list[k] = nil
			self:updatePlayerNum()
			print("踢走掉线 o#######",k,v.disconnect,v.chip,self.minChip)
		end
	end
end

--离线清除
function MachineBase:removeDisconnect()
	for k,v in pairs(self.player_list) do 
		if v.disconnect then 	
			self:sitUp(k)
			self.player_list[k] = nil
			self:updatePlayerNum()
			--清除玩家所在桌子id
			self:sendGate(v, 'update_tableid', 0)	
			print("踢走离线#######",k)		
		end
	end
end

--清除没准备的
function MachineBase:removeNoReady()
	for k,v in pairs(self.player_list) do 
		if not v.ready then 	
			self:sitUp(k)
			self.player_list[k] = nil
			self:updatePlayerNum()
			--清除玩家所在桌子id
			self:sendGate(v, 'update_tableid', 0)	
			print("清除没准备的#######",k)		
		end
	end
end


--取seatplayer
function MachineBase:getSeatPlayer(player)
	local seatPlayer = {}
	seatPlayer.seatid = player.seatid
	seatPlayer.playerid = player.playerid
	seatPlayer.nick = player.nick or '无名字'
	seatPlayer.chip = player.chip
	seatPlayer.diamond = player.diamond
	seatPlayer.icon = player.icon
	seatPlayer.viplevel = player.viplevel
	seatPlayer.level = player.level
	seatPlayer.sex = player.sex
	seatPlayer.playing = player.playing

	return seatPlayer
end

--取所有seatplayer
function MachineBase:getSeatPlayers()
	local seatPlayers = {}	
	for k,playerid in pairs(self.seat_list) do 
		local seatPlayer = {}
		local player = self.player_list[playerid]
		seatPlayer.seatid = player.seatid
		seatPlayer.playerid = player.playerid
		seatPlayer.nick = player.nick
		seatPlayer.chip = player.chip
		seatPlayer.diamond = player.diamond
		seatPlayer.icon = player.icon
		seatPlayer.viplevel = player.viplevel
		seatPlayer.level = player.level
		seatPlayer.playing = player.playing
		-- print("=======seatPlayer", seatPlayer)
		table.insert(seatPlayers,seatPlayer)
	end
	-- print("---------------->seatPlayers", seatPlayers)
	return seatPlayers
end

--取当前正在局里玩家数
function MachineBase:getPlayingNum()
	local num = 0
	for k, v in pairs(self.player_list) do 
		if self:isPlaying(v) then 
			num = num + 1
		end
	end	
	return num 
end

--取当前正在局里玩家数
function MachineBase:getReadyNum()
	local num = 0
	for k,v in pairs(self.player_list) do 
		if not v.disconnect and v.ready then 
			num = num + 1
		end
	end
	return num 
end

--是否正在局中玩
function MachineBase:isPlaying(player)
	if player and player.playing  then 
		return true
	end
	return false
end

--通过座位取玩家
function MachineBase:getPlayerBySeat(seatid)
	local playerid = self.seat_list[seatid]
	if not playerid then return end
	return self.player_list[playerid]
end


---------------------------------------------------------
-- 发送消息
---------------------------------------------------------
--需要返回的请求
function MachineBase:callGate(player,cmd,data,reason)
	return self.nodeMessage:callGate(player.nodename,player.playerid,cmd,data,reason)
end

function MachineBase:sendGate(player,cmd,data)
	self.nodeMessage:sendGate(player.nodename,player.playerid,cmd,data)
end

--给指定玩家发消息
function MachineBase:sendMessage(playerid,data)
	local player = self.player_list[playerid]
	if not player or player.disconnect then 
		return
	end	
	self.nodeMessage:broadcastGate(player.nodename,{playerid},data)
end

--给指定玩家发消息
function MachineBase:callMessage(playerid,data)
	local player = self.player_list[playerid]
	if not player or player.disconnect then 
		return
	end	
	self.nodeMessage:callBroadcastGate(player.nodename,{playerid},data)
end

--给所有在线玩家发消息
function MachineBase:sendToAll(data)
	local playerList = {}	
	for k,v in pairs(self.player_list) do 
		if not v.disconnect  then 
			table.insert(playerList,k)
		end
	end
	if next(playerList) then
		self.nodeMessage:broadcastAllGate(playerList, data)
	end
end

--给别的玩家发消息
function MachineBase:sendToOther(playerid,data)
	local playerList = {}
	for k,v in pairs(self.player_list) do 
		if not v.disconnect and k ~= playerid then 	
			table.insert(playerList,k)
		end
	end
	if next(playerList) then
		print("----------------------->playerList", playerList, data)
		self.nodeMessage:broadcastAllGate(playerList, data)
	end
end

--给无座玩家发消息
function MachineBase:sendToNoSeat(data)
	local playerList = {}
	local bAdd = false
	for k,v in pairs(self.player_list) do 
		bAdd = true
		for seatid,playerid in pairs(self.seat_list) do 			
			if k == playerid then 	
				bAdd = false
				break
			end
		end
		if bAdd and not v.disconnect then 	
			table.insert(playerList,k)
		end			
	end		
	if next(playerList) then 
		self.nodeMessage:broadcastAllGate(playerList, data)
	end
end

function MachineBase:reconnect(playerid)
	-- return self.tbMessage[playerid]
end


---------------------------------------------------------
-- 状态
---------------------------------------------------------


---------------------------------------------------------
-- public
---------------------------------------------------------
--取桌子id
function MachineBase:getTableId()
	return self.tableid
end

--取玩家
function MachineBase:getPlayer(playerid)
	if not playerid then return nil end
	return self.player_list[playerid]
end

--加入玩家
function MachineBase:addPlayer(player)
	print("______________MachineBase:addPlayer", player)
	self.player_list[player.playerid] = player
	self:updatePlayerNum()
end

--取玩家座位id
function MachineBase:getPlayerSeatId(playerid)
	for k, v in pairs(self.seat_list) do 
		if v == playerid then
			return k
		end
	end
	return nil
end

--@override
function MachineBase:sitDownCallback( playerid )
	-- --print(player)
	-- local seatPlayer = self:getSeatPlayer(player)
	-- local data = {nt_seat_change = {
	-- 	tableid = self.tableid,
	-- 	seatid = seatid,
	-- 	seat_player = seatPlayer,
	-- 	playerid = playerid,
	-- 	leave = false,
	-- }}
	-- self:sendToOther(playerid,data)
	-- self:updatePlayerNum()
end

--坐下
function MachineBase:sitDown(playerid,seatid)
	local tbSeat = {}
	if seatid  then 
		local playerid = self.seat_list[seatid] 
		if not playerid or playerid == 0 then 
			table.insert(tbSeat,seatid)
		else
			print("-------------------------------1", playerid,seatid, self.seat_list)
			return
		end
	else
		for id=1,self.maxSeatNum do 
			seatid = self.seat_list[id]
			if not seatid or seatid == 0 then 
				table.insert(tbSeat,id)
			end
		end
	end
	mix_array(tbSeat) --随机位置	
	if #tbSeat > 0 then 
		seatid = tbSeat[1]
	else
		return false
	end
	local player = self.player_list[playerid]
	if player.seatid then
		self:sitUp(playerid)
	end
	if player then
		self.seat_list[seatid] = playerid
		player.seatid = seatid
	end

	self:sitDownCallback(playerid)
	return seatid
end

--@override
function MachineBase:sitUpCallback( seatid, playerid )
	-- local data = {nt_seat_change = {
	-- 	tableid = self.tableid,
	-- 	seatid = seatid,
	-- 	leave = true,
	-- }}
	-- self:sendToAll(data)
	-- self:updatePlayerNum()
end
--离座
function MachineBase:sitUp(playerid)
	if not playerid or playerid <=0 then
		return false
	end	
	local player = self.player_list[playerid]
	if not player then
		return false
	end
	local seatid = player.seatid
	-- self.player_list[playerid] = nil
	self:sitUpCallback(seatid, playerid)

	if seatid then 
		self.seat_list[seatid] = nil		
	end
	player.seatid = nil	
	return true
end

--配牌
function MachineBase:setGmCard(playerid,cards,repeatNum)
	self.tbCheatNum[playerid] = repeatNum or 0
	if repeatNum  == 0 then
		self.gmcards[playerid] = {}
	else
		self.gmcards[playerid] = cards
	end
	print("_______cards#################___________________",cards)
end


----------------------------------
-- 数据库操作
----------------------------------
function MachineBase:calldb(cmd,...)	
	self.nodeMessage:callService('dbmgr_service',cmd,...)
end

function MachineBase:senddb(cmd,...)
	self.nodeMessage:sendService('dbmgr_service',cmd,...)
end

--取库存表
function MachineBase:getStock()
	local stock = self:calldb('get_stock',self.gameid)
	if not next(stock) then 
		stock = {
			gameid=self.gameid,
			pool = 0,
			bottom = 1000,
			top = 100000,
			tip = 0,
		}
		self:calldb('add_stock',stock)		
		stock = self:calldb('get_stock',self.gameid)
	end
	self.stock = stock	
end

function MachineBase:setStock()
	--机器人库存更新
	local system_earn,tip = self:robotSettlement()		
	if system_earn ~= 0 then 
		self.stock.pool = self.stock.pool + system_earn
		self.stock.tip = self.stock.tip + tip
		self:senddb('update_stock',self.stock)	
	end
end

-- --计算机器人输赢
-- function MachineBase:robotSettlement()
-- end

-- --检查库存
-- function MachineBase:checkStock()
-- end

-------------------------------------------------------------------------------
-- 牌局记录
-------------------------------------------------------------------------------

-----------------------------------------------------------------------------------
----------------------------------
-- 数据操作
----------------------------------
--当前操作所剩余的时间
function MachineBase:getOperTime()
	local curState = self:getState()
	if not curState or not self.stateTime[curState] then 
		return 0
	end
	local time = self.stateTime[curState] - (os.time() - self.operStartTime)
	if time < 0 then 
		time = 0
	end
	return time
end

--当前状态
function MachineBase:getState()
	return self.fsm:get()
end

--桌子相关配置
-- function MachineBase:getConfig()
-- end

--进入桌子
function MachineBase:enterTable(playerid)
	log.debug('玩家进入牌桌>>>>>>>>>>>',player_id,self.tableid)
end

--离开桌子
function MachineBase:leaveTable(playerid)
	log.debug('玩家离开牌桌>>>>>>>>>>>',playerid,self.tableid)
	return self:sitUp(playerid)
end

--掉线处理
function MachineBase:disconnect(playerid)	
	local player = self.player_list[playerid]
	log.debug('玩家掉线>>>>>>>>>>>',playerid,self.tableid,player.playing,player.disconnect)
	--旁观者掉线马上踢出大厅
	if not player.playing and player.disconnect then 
		print("########在旁观玩家中直接踢走")	
		self:sendGate(player, 'update_tableid', 0)
		self:sitUp(playerid)
		return true
	end	
	return false
end

--关闭服务
function MachineBase:exit()
	self.nodeMessage:sendService('.proxy','clear_table',self.tableid)
	skynet.fork(function()
		skynet.sleep(200)
		skynet.exit()
	end)
end

--安全关服务
function MachineBase:setClose(close)

	--定时踢出所有玩家后，关服
	self.close = close
	if not self.closeHandler then 
		self.timer:unregister(self.closeHandler)
		self.closeHandler = nil
	end
	if close then 
		local maxDelay = 5*60 --最大的等待时间
		local delay = 0
		local callback = function()
			delay = delay + 1
			if delay > maxDelay then
				self.fsm:fire('to_rest') 
				self.fsm:set('rest')
				self:onRest()
			end
			if self:getState() ~= "rest" and self:getState() ~= "wait" then 
				return
			end
			for k,v in pairs(self.player_list) do 
				if close then 				
					local data = {nt_kick_table = {
						playerid = k,
						content = '游戏正在维护！',
					}}
					self:sendMessage(k,data)	
					--设置玩家所在桌子id为0	
					self:sendGate(v, 'update_tableid', 0)
					self:sitUp(k)
					self.player_list[k] = nil
					self:updatePlayerNum()
				end
			end		
			self.timer:unregister(self.closeHandler)			
			self:exit()
		end
		--1局玩完后关游戏
		self.closeHandler = self.timer:register(1 , nil, callback,true)
	end	
end

  -- `uwincnt` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '赢牌次数',
  -- `ulosecnt` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '输牌次数',
  -- `udrawcnt` int(11) NOT NULL DEFAULT '0' COMMENT '和局次数',
  -- `win_streak` int(11) NOT NULL DEFAULT '0' COMMENT '最大连续胜局次数',
--玩游戏次数写入
function MachineBase:writeUserInfo(player)
	local sql = string.format("update usergame set uwincnt= %d, ulosecnt= %d,udrawcnt= %d, cur_win_streak= %d, win_streak= %d where uid=%d",
		player.uwincnt,player.ulosecnt,player.udrawcnt,player.cur_win_streak,player.win_streak ,player.playerid)

	self.nodeMessage:sendService("mysql_service",'execute',sql)
end

function MachineBase:readUserInfo(player)
	local sql = string.format("select * from usergame where uid=%d",
		player.playerid)
	local res = self.nodeMessage:callService("mysql_service",'execute',sql)
	if res and next(res) then
		res = res[1]	
		player.uwincnt = res.uwincnt
		player.ulosecnt = res.ulosecnt
		player.udrawcnt = res.udrawcnt
		player.cur_win_streak = res.cur_win_streak
		player.win_streak = res.win_streak --连续赢的次数
	end
end
----------------------------------------------------------------------------------------------
---------开始游戏
---------------------------------------------------------------------------------------------- 
-- function MachineBase:start()
-- 	self.fsm:set("settlement")
-- 	self.fsm:fire("to_rest")
-- end

return MachineBase